/*
 * dbasesRoot.java
 *
 * Created on May 18, 2006, 2:08 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 * 
 * 13, Feb 2009
 *              the method processTreeHierarchy now prevents to process a null
 *              databaseObject.
 * 22, Feb 2011
 *              Method rump up; the global variable sDriver was renamed to sUrl in order to describe more accuretly its function as a
 *              connection argument.
 *              Begin with multiple sql driver support.
 * 19, Mar 2012
 *              In order to transition to the factory pattern, the class converted to abstract
 * 16, Feb 2014 Some trivial changes in order to make the code compatible with java 1.7
 */

package portfolio.dbHost;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Vector;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import portfolio.dbHost.dataBases.DBase;
import portfolio.dbHost.project.Project;
import portfolio.configMessage.configMessageEvent;
import portfolio.configMessage.configMessageFrame;
import portfolio.configMessage.configMessageListener;

import portfolio.mainScreen;

/**
 *
 * @author ACA
 */
public abstract class Host implements configMessageListener, MouseListener
{
    private mainScreen         mainFrame  = null;
    private configMessageFrame msgFrame   = null;

    protected final static String DB_DRIVER_MYSQL = "mysql";
    protected final static String DB_DRIVER_ODBC  = "odbc";
    
    public final static int DB_TYPE_MYSQL   = 0;
    public final static int DB_TYPE_ODBC    = 1;
    public final static int DB_TYPE_UNKNOWN = -1;

    private int       iDBType         = DB_TYPE_UNKNOWN;
    
    private Connection  connection        = null;
//    private Vector      vDBases           = null;
    protected Vector      vDBases           = null;
    private int         iDBasesCount      = 0;
//    private DBase[]     dataBases;
    protected DBase[]     dataBases;
    private Project     project           = null;
    
    private JTree       dbaseTree         = null;
    private DBTreeTab   dbTreeTab         = null;

    final static protected String ACTION_LOGON_DB  = "Logon DB";
    final static protected String ACTION_CREATE_DB = "Create DB";

    private String       sUrl            = "jdbc:" + DB_DRIVER_MYSQL + ":";
    private String       sHost           = "localhost";
    private String       sDataSourceName = "BMVstocks";  //for MySQL, this is a DB name
    private String       sUser           = "root";
    private String       sPassword       = "**********";
    
    /**
     *
     * @param e 
     */
    public abstract void okSelected     (configMessageEvent e);
    /**
     *
     *
     * @throws java.sql.SQLException
     */
    public void printConnectionMetadata () throws SQLException
    {
        if (connection == null) {
            mainFrame.displayMessage("Host.printConnectionCatalog", "null DB connection.");
            return;
        }
        String sCatalog = connection.getCatalog();
        mainFrame.displayMessage("Host.printConnectionCatalog", "Catalog: " + sCatalog);

        String sPrintUrl = connection.getMetaData ().getURL();
        mainFrame.displayMessage("Host.printConnectionCatalog", "Url: " + sPrintUrl);

        String sProductName = connection.getMetaData().getDatabaseProductName();
        mainFrame.displayMessage("Host.printConnectionCatalog", "DB Product name: " + sProductName);

        String sUser = connection.getMetaData().getUserName();
        mainFrame.displayMessage("Host.printConnectionCatalog", "User: " + sUser);

    }
    /**
     *
     * @param dBasePanel
     * @throws java.lang.Exception
     */
    public void setDBTree (JPanel dBasePanel) throws Exception
    {
        dbTreeTab = new DBTreeTab (dBasePanel);
        dbTreeTab.initComponents (this);
    }
    /**
     *
     * @throws java.lang.Exception
     */
    public void updateDBTree () throws Exception
    {
        JPanel dBasePanel = mainFrame.getDBasePanel();

        if (dBasePanel == null) {
            throw new Exception ("null dBasePanel.");
        }
        dBasePanel.removeAll();
        this.setDBTree (dBasePanel);
    }
    /**
     *
     *
     * @return 
     */
    public DBTreeTab getDBTree ()
    {
        return dbTreeTab;
    }
    /**
     *
     * @param e 
     */
    public void cancelSelected (configMessageEvent e) 
    {
        msgFrame.dispose();
    }
    /**
     * Mouse listener abstract members:
     *  mouseClicked, mousePressed, mouseReleased, mouseEntred.
     * @param arg0
     */
    public void mouseClicked(MouseEvent arg0) {
//        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void mousePressed(MouseEvent arg0) {
//        throw new UnsupportedOperationException("Not supported yet.");
        try {
            Object o = arg0.getSource();
            JMenuItem jTempMenuItem = (JMenuItem) o;

            String sComand = jTempMenuItem.getActionCommand();
            if (sComand.equals (Host.ACTION_CREATE_DB)) {
                msgFrame = new configMessageFrame (mainFrame, Host.ACTION_CREATE_DB, 250, 120);
                msgFrame.showMessageFrame();
                msgFrame.addConfigMessageListener(this);
            }
        } catch (Exception ex) {
            mainFrame.displayMessage("Host.mousePressed 130", ex.getMessage());
        }
    }

    public void mouseReleased(MouseEvent arg0) {
//        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void mouseEntered(MouseEvent arg0) {
//        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void mouseExited(MouseEvent arg0) {
//        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    /**
     * Creates a new instance of DBase
     * @param mainFrameParam 
     * @throws java.lang.Exception 
     */
    public Host (mainScreen mainFrameParam) throws Exception
    {
        mainFrame = mainFrameParam;
        if (mainFrame == null)
            throw new Exception ("null mainFrame parameter.");
    } /* end constructor DBase */
    /*
     * 
     * 
     */
    public configMessageFrame getMsgFrame ()
    {
        return msgFrame;
    }
    /*
     * 
     * 
     */
    public mainScreen getMainFrame ()
    {
        return mainFrame;
    }
    /**
     *
     * @param iDbTypeParam
     * @param sUrl
     * @param sHost
     * @param sDataSourceName
     * @param sUser
     * @param sPasswd
     * @return
     * @throws Exception
     */
    public abstract Connection connectToDB (int iDbTypeParam, // <----- & non static
                                          String sUrl,
                                          String sHost, 
                                          String sDataSourceName,
                                          String sUser,
                                          String sPasswd) throws Exception;
    /**
     * 
     * 
     * @param connectionParam
     */
    protected void setConnection (Connection  connectionParam)
    {
        connection = connectionParam;
        // 0j0 Warn NULL connection
    }
    /*
     * 
     * 
     */
    protected void setUrl (String sUrlParam)
    {
        sUrl = sUrlParam;
    }
    /*
     * 
     * 
     */
    protected void setHost (String sHostParam)
    {
        sHost = sHostParam;
    }
    /*
     * 
     * 
     */
    protected void setDataSourceName (String sDataSourceNameParam)
    {
        sDataSourceName = sDataSourceNameParam;
    }
    /*
     * 
     * 
     */
    protected void setUser (String sUserParam)
    {
        sUser = sUserParam;
    }
    /*
     * 
     * 
     */
    protected void setPassword (String sPasswordParam)
    {
        sPassword = sPasswordParam;
    }
    /*
     * 
     * 
     */
    protected void setDBtype (int iDBTypeParam)
    {
        iDBType = iDBTypeParam;
    }
    /**
     *
     *
     */
//    private int getDBType (String sURL)
//    {
//        sURL.toLowerCase();
//        if (sURL.contains(":" + DB_DRIVER_MYSQL + ":") == true) {
//            return DB_TYPE_MYSQL;
//        }
//        if (sURL.contains (":" + DB_DRIVER_ODBC + ":") == true) {
//            return DB_TYPE_ODBC;
//        }
//        return DB_TYPE_UNKNOWN;
//    }
    /**
     *
     *
     * @return 
     */
    public int getDBType ()
    {
        return iDBType;
    }
    /**
     *
     * @return 
     */
    public Connection getConnection ()
    {
        return connection;
    }
    /**
     *
     * @return 
     */
    public String getHostServer ()
    {
        return sHost;
    }
    /**
     *
     * @return 
     */
    public int getDBasesCounter ()
    {
        return iDBasesCount;
    }
    /**
     *
     * @param iIdx 
     * @return 
     * @throws java.lang.Exception 
     */
    public DBase getTable (int iIdx) throws Exception
    {
        if (iIdx < 0 || iIdx > iDBasesCount)
            throw new Exception ("improper index.");
        
        return dataBases [iIdx];
    }
    /**
     *
     * @param sDBaseName 
     * @return 
     */
    public DBase getTable (String sDBaseName)
    {
        if (!vDBases.contains (sDBaseName))
            return null;
        
        int iDBaseIndex = vDBases.indexOf(sDBaseName);
        
        return dataBases [iDBaseIndex];        
    }
    /**
     *
     * @param sDBaseName 
     * @return 
     */
    public int getTableIndex (String sDBaseName)
    {
        if (!vDBases.contains(sDBaseName))
            return 0;
        
        return vDBases.indexOf(sDBaseName);
    }
    /**
     *
     * @return 
     */
    public DefaultMutableTreeNode processTreeHierarchy ( ) 
    {
        DefaultMutableTreeNode node = new DefaultMutableTreeNode (sHost);
        DefaultMutableTreeNode child = null;
        
        if (dataBases != null) {
            for (int i = 0; i < dataBases.length; i++) {
                child = dataBases [i].processTreeHierarchy();
                if (child != null)
                    node.add (child);
            }
        }
        return (node);
    } /* end method processHierarchy */
    /**
     *
     * @param dbTreeParam 
     * @param iXPos 
     * @param iYPos 
     * @return 
     * @throws java.lang.Exception 
     */
    public Vector getPopupOptions (JTree dbTreeParam, int iXPos, int iYPos) throws Exception
    {
        if (dbTreeParam == null)
            throw  new Exception ("JTreeParam null.");
        dbaseTree = dbTreeParam;
        
        Vector vOut = new Vector ();
        vOut.add("<server>");        

        JPopupMenu treeOptionsMenu = new JPopupMenu ("Options");
        dbaseTree.add(treeOptionsMenu);

        JMenuItem jItem = new JMenuItem (Host.ACTION_CREATE_DB);
        jItem.addMouseListener (this);
        treeOptionsMenu.add (jItem); 
        treeOptionsMenu.setLocation (iXPos, iYPos);
        treeOptionsMenu.show (treeOptionsMenu, iXPos, iYPos);

        return vOut;
    } /* end method getPopupOptions */    
    /**
     *
     * @param oPathParam 
     * @return 
     */
    public Object getTreeObject (Object [] oPathParam)
    {
        if (oPathParam == null) {
            mainFrame.displayMessage("Host.getTreeObject 336", "error, no path param");
            return null;
        }
        if (oPathParam.length < 1) {
            mainFrame.displayMessage("Host.getTreeObject 340", "error, wrong path length");
            return null;
        }
        if (!oPathParam [0].toString().equals(sHost)) {
            mainFrame.displayMessage("Host.getTreeObject 344", "error, no root server found");
            return null;
        }
        if (oPathParam.length != 1) {
            String sDataBase = oPathParam [1].toString();
            int iIdx = vDBases.indexOf(sDataBase);
            if (iIdx != -1) {
                return dataBases[iIdx].getTreeObject (oPathParam);
            } else {
                mainFrame.displayMessage("Host.getTreeObject 353", "error, no database found");
                return null;
            }
        }
        return this;
    } /* end method getTreeObject */
    /**
     * 
     * @throws java.lang.Exception 
     */
    public abstract void buildDBTree ( ) throws Exception; 
    /**
     *
     * @param tmpConnection
     * @throws java.lang.Exception
     */    
    public static void shutDown (Connection tmpConnection) throws Exception
    {
	try {
	    tmpConnection.close ();
	}
	catch ( SQLException sqlex ) {
            throw new Exception ("portfolioDB::shutdown: Error while tying to close DB:" + sqlex);
	}
    } /* End Method shutDown */
    /**
     *
     * @throws java.lang.Exception 
     */
    public void shutDown () throws Exception
    {
        if (connection != null)
            Host.shutDown (connection);
        
        connection = null;
    } 
    /**
     *
     * @return 
     */
    public mainScreen getMainScreen ()
    {
        return mainFrame;
    }
    /**
     *
     * @param projectParam
     */
    public void setProject (Project projectParam)
    {
        project = projectParam;
    }
    /**
     *
     * @return
     */
    public Project getProject ()
    {
        return project;
    }
    /**
     *
     * @return 
     * @throws java.lang.Exception 
     */
    public Vector getProjects () throws Exception
    {
        if (vDBases == null)
            return null;
        
        Vector vProjects =  (Vector) vDBases.clone();
        int iSize = vProjects.size();
        if (iSize <= 0)
            return null;

        for (int iIdx = iSize -1; iIdx >= 0; iIdx--) {
            if (dataBases [iIdx] != null) {
                DBase dBase = dataBases [iIdx];
////                Connection connection = this.getConnection();
//                String sDBName = dBase.getDBName();
                boolean bPrjFlag = Project.isProject (dBase); //connection, sDBName);
                if (bPrjFlag == false) {
                    vProjects.remove (iIdx);
                }
            }
        }
        return vProjects;
    }
     /******************************************************************
     * Protected against SQL injection
     * @param connectionParam
     * @param sDataBase
     * @throws java.lang.Exception
     ******************************************************************/
    static public void createDB (Connection connectionParam, String sDataBase) throws Exception
    {
        if (connectionParam == null)
            throw new Exception ("No connection provided.");
        if (sDataBase == null)
            throw new Exception ("No data base name provided.");
        if (sDataBase.length() <= 0)
            throw new Exception ("Data Base name length <= 0.");
        
        try {
            PreparedStatement pstmt = connectionParam.prepareStatement("CREATE DATABASE " + sDataBase);
            pstmt.execute ();            
        } catch (SQLException sqlex) {
            throw new Exception (sqlex);
        }
    }  
    /**
     * 
     * @param sDataBase
     * @throws java.lang.Exception
     */
    public void createDB (String sDataBase) throws Exception
    {
        Host.createDB(connection, sDataBase);
    }
    /**
     *
     * @param sDBNameParam 
     * @return 
     */
    public DBase getDB (String sDBNameParam)
    {
        if (vDBases == null)
            return null;
        
        if (!vDBases.contains(sDBNameParam)) {
            return null;
        }
        int iDBaseIdx = vDBases.indexOf(sDBNameParam);
        
        return dataBases [iDBaseIdx];        
    }
    /**
     * the mysql statement "show databases" is not conformant with SQL standard
     * @return 
     * @throws java.lang.Exception
     */
    public abstract Vector showDBs () throws Exception;
} /* end class DBase */
